{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Table A7 (Appendices)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loaded: jcr_mutiny_conflict_data.dta  |  Rows=1,599,624  Cols=60\n",
      "\\begin{table}\n",
      "\\caption{}\n",
      "\\label{}\n",
      "\\begin{center}\n",
      "\\begin{tabular}{llllll}\n",
      "\\hline\n",
      "                    & m13        & m14        & m15        & m16        & m17        \\\\\n",
      "\\hline\n",
      "Military mutiny           & 0.409***   & 0.407***   & 0.405***   & 0.408***   & 0.425***   \\\\\n",
      "                    & (0.097)    & (0.097)    & (0.099)    & (0.100)    & (0.102)    \\\\\n",
      "Military spending per soldier (logged)  & 0.047**    & 0.040**    & 0.033*     & 0.061***   & 0.026      \\\\\n",
      "                    & (0.019)    & (0.019)    & (0.019)    & (0.019)    & (0.020)    \\\\\n",
      "Military personnel (logged)         & 0.640***   & 0.635***   & 0.638***   & 0.622***   & 0.465***   \\\\\n",
      "                    & (0.021)    & (0.021)    & (0.022)    & (0.022)    & (0.022)    \\\\\n",
      "Years since last coup  & 0.001      & 0.001      & 0.002      & -0.001     & -0.001     \\\\\n",
      "                    & (0.002)    & (0.002)    & (0.002)    & (0.002)    & (0.002)    \\\\\n",
      "Defense alliance (target)     & -0.324***  & -0.330***  & -0.327***  & -0.041     & -0.370***  \\\\\n",
      "                    & (0.051)    & (0.051)    & (0.053)    & (0.056)    & (0.057)    \\\\\n",
      "Defense alliance (challenger) &            & -0.293***  & -0.305***  & 0.017      & -0.397***  \\\\\n",
      "                    &            & (0.049)    & (0.050)    & (0.053)    & (0.053)    \\\\\n",
      "Capability ratio             & 2.689***   & 2.720***   & 2.739***   & 2.681***   & 1.947***   \\\\\n",
      "                    & (0.091)    & (0.090)    & (0.091)    & (0.092)    & (0.092)    \\\\\n",
      "Both democracy     \n",
      "...\n",
      "\n",
      "LaTeX table written to: C:\\Users\\rmuhi\\OneDrive\\Desktop\\Mutiny_Conflict Paper_All\\Replication File\\logit_results_table7.tex\n"
     ]
    }
   ],
   "source": [
    "# ----------------------------------------------------------\n",
    "# 0) Lightweight installer if packages are missing\n",
    "# ----------------------------------------------------------\n",
    "\n",
    "try:\n",
    "    import pandas as _pd; import statsmodels as _sm; import matplotlib as _mpl\n",
    "except Exception:\n",
    "    import sys, subprocess\n",
    "    subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-U\", \"pandas\", \"statsmodels\", \"matplotlib\"])\n",
    "\n",
    "from pathlib import Path\n",
    "import pandas as pd\n",
    "import statsmodels.formula.api as smf\n",
    "from statsmodels.iolib.summary2 import summary_col\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 1) Load data\n",
    "# ----------------------------\n",
    "file_path = Path(r\"C:\\Users\\rmuhi\\OneDrive\\Desktop\\Mutiny_Conflict Paper_All\\Replication File\\jcr_mutiny_conflict_data.dta\")\n",
    "if not file_path.exists():\n",
    "    raise FileNotFoundError(f\"Could not find .dta file at: {file_path}\")\n",
    "\n",
    "data = pd.read_stata(file_path)\n",
    "print(f\"Loaded: {file_path.name}  |  Rows={len(data):,}  Cols={len(data.columns)}\")\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 2) (Optional) sort for consistency\n",
    "# ----------------------------\n",
    "if {'id', 'year'}.issubset(data.columns):\n",
    "    data = data.sort_values(['id', 'year'])\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 3) Model formulas \n",
    "# ----------------------------\n",
    "formula13 = (\n",
    "    'dispute ~ mutiny_t + lmmilex_persol_t + lmmilper_t + years_since_coup + '\n",
    "    'defense_target + capprop + jdem + majorpower + ucdp_civconf_t2 + '\n",
    "    'cold_war + t_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "formula14 = (\n",
    "    'dispute ~ mutiny_t + lmmilex_persol_t + lmmilper_t + years_since_coup + '\n",
    "    'defense_target + defense_challenger + capprop + jdem + majorpower + '\n",
    "    'ucdp_civconf_t2 + cold_war + t_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "formula15 = (\n",
    "    'dispute ~ mutiny_t + lmmilex_persol_t + lmmilper_t + years_since_coup + '\n",
    "    'conscript_t + defense_target + defense_challenger + capprop + jdem + '\n",
    "    'majorpower + ucdp_civconf_t2 + cold_war + t_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "formula16 = (\n",
    "    'dispute ~ mutiny_t + lmmilex_persol_t + lmmilper_t + years_since_coup + '\n",
    "    'conscript_t + defense_target + defense_challenger + capprop + jdem + '\n",
    "    'majorpower + ucdp_civconf_t2 + s_un_atop_ddy + cold_war + '\n",
    "    't_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "formula17 = (\n",
    "    'dispute ~ mutiny_t + lmmilex_persol_t + lmmilper_t + years_since_coup + '\n",
    "    'conscript_t + defense_target + defense_challenger + capprop + jdem + '\n",
    "    'majorpower + ucdp_civconf_t2 + s_un_atop_ddy + cold_war + mindist_ddy + '\n",
    "    't_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 4) Fit helper (HC1-robust, with fallback)\n",
    "# ----------------------------\n",
    "def fit_logit_robust(formula, df):\n",
    "    model = smf.logit(formula, df)\n",
    "    try:\n",
    "        res = model.fit(disp=False, cov_type='HC1')\n",
    "    except TypeError:\n",
    "        # Older statsmodels versions might not accept cov_type in fit()\n",
    "        res0 = model.fit(disp=False)\n",
    "        res = res0.get_robustcov_results(cov_type='HC1')\n",
    "    return res\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 5) Fit models \n",
    "# ----------------------------\n",
    "result13 = fit_logit_robust(formula13, data)\n",
    "result14 = fit_logit_robust(formula14, data)\n",
    "result15 = fit_logit_robust(formula15, data)\n",
    "result16 = fit_logit_robust(formula16, data)\n",
    "result17 = fit_logit_robust(formula17, data)\n",
    "\n",
    "results = [result13, result14, result15, result16, result17]\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 6) Build LaTeX table\n",
    "# ----------------------------\n",
    "regressor_order = [\n",
    "    'mutiny_t',\n",
    "    'lmmilex_persol_t',\n",
    "    'lmmilper_t',\n",
    "    'years_since_coup',\n",
    "    'conscript_t',\n",
    "    'defense_target',\n",
    "    'defense_challenger',\n",
    "    'capprop',\n",
    "    'jdem',\n",
    "    'majorpower',\n",
    "    'ucdp_civconf_t2',\n",
    "    's_un_atop_ddy',\n",
    "    'cold_war',\n",
    "    'mindist_ddy',\n",
    "    'Intercept'  # will be renamed if shows as 'const'\n",
    "]\n",
    "\n",
    "info_dict = {\n",
    "    'N':         lambda x: f\"{int(x.nobs):d}\",\n",
    "    'Pseudo R²': lambda x: f\"{getattr(x, 'prsquared', float('nan')):.3f}\"\n",
    "}\n",
    "\n",
    "tbl = summary_col(\n",
    "    results=results,\n",
    "    float_format='%0.3f',\n",
    "    stars=True,\n",
    "    model_names=['m13','m14','m15','m16','m17'],\n",
    "    info_dict=info_dict,\n",
    "    regressor_order=regressor_order,\n",
    "    drop_omitted=True  # hide time polynomials from the body if not in order list\n",
    ")\n",
    "\n",
    "latex_lines = tbl.as_latex().splitlines()\n",
    "\n",
    "# Insert extra rows immediately after the Pseudo R² line\n",
    "insert_idx = next((i for i, ln in enumerate(latex_lines) if 'Pseudo R²' in ln), None)\n",
    "if insert_idx is not None:\n",
    "    checks = ' & ' + ' & '.join(['\\\\checkmark'] * len(results)) + r' \\\\'\n",
    "    for new_line in [r\"Time polynomials\" + checks,\n",
    "                     r\"Robust SE\" + checks]:\n",
    "        insert_idx += 1\n",
    "        latex_lines.insert(insert_idx, new_line)\n",
    "\n",
    "# Friendly labels (handle escaped & unescaped)\n",
    "replacements = {\n",
    "    'mutiny_t':                 'Military mutiny',\n",
    "    'mutiny\\\\_t':               'Military mutiny',\n",
    "\n",
    "    'lmmilex_persol_t':         'Military spending per soldier (logged)',\n",
    "    'lmmilex\\\\_persol\\\\_t':     'Military spending per soldier (logged)',\n",
    "\n",
    "    'lmmilper_t':               'Military personnel (logged)',\n",
    "    'lmmilper\\\\_t':             'Military personnel (logged)',\n",
    "\n",
    "    'years_since_coup':         'Years since last coup',\n",
    "    'years\\\\_since\\\\_coup':     'Years since last coup',\n",
    "\n",
    "    'conscript_t':              'Conscription',\n",
    "    'conscript\\\\_t':            'Conscription',\n",
    "\n",
    "    'defense_target':           'Defense alliance (target)',\n",
    "    'defense\\\\_target':         'Defense alliance (target)',\n",
    "\n",
    "    'defense_challenger':       'Defense alliance (challenger)',\n",
    "    'defense\\\\_challenger':     'Defense alliance (challenger)',\n",
    "\n",
    "    'capprop':                  'Capability ratio',\n",
    "\n",
    "    'jdem':                     'Both democracy',\n",
    "\n",
    "    'majorpower':               'Major power',\n",
    "\n",
    "    'ucdp_civconf_t2':          'Civil conflict',\n",
    "    'ucdp\\\\_civconf\\\\_t2':      'Civil conflict',\n",
    "\n",
    "    's_un_atop_ddy':            'UN voting similarity',\n",
    "    's\\\\_un\\\\_atop\\\\_ddy':      'UN voting similarity',\n",
    "\n",
    "    'cold_war':                 'Cold War',\n",
    "    'cold\\\\_war':               'Cold War',\n",
    "\n",
    "    'mindist_ddy':              'Minimum distance',\n",
    "    'mindist\\\\_ddy':            'Minimum distance',\n",
    "\n",
    "    'Intercept':                'Constant',\n",
    "    'const':                    'Constant'\n",
    "}\n",
    "\n",
    "fixed_lines = []\n",
    "for line in latex_lines:\n",
    "    for old, new in replacements.items():\n",
    "        if old in line:\n",
    "            line = line.replace(old, new)\n",
    "    fixed_lines.append(line)\n",
    "\n",
    "custom_latex = \"\\n\".join(fixed_lines)\n",
    "\n",
    "# Preview and save\n",
    "print(custom_latex[:1500] + \"\\n...\\n\")\n",
    "out_tex = file_path.parent / \"table_A7.tex\"\n",
    "out_tex.write_text(custom_latex, encoding=\"utf-8\")\n",
    "print(f\"LaTeX table written to: {out_tex}\")\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
